from flask import g
from flask import request
from flask_restful import Resource,fields,marshal
from flask_restful import current_app,abort
from flask_restful import reqparse
import time
from flask_restful.reqparse import RequestParser
from flask_restful import inputs

from toutiao import db
from cache.user import UserProfileCache,UserArticeAttitudeCache, UserHistoryCache
from models.news import Article, Collection
from cache.article import ArticleDetailCache
from models.user import User, Relation
from toutiao.utils.decorators import loginrequired
from cache.user import UserFollowingCache
from models.news import Attitude
from toutiao.apps.home import constants
from cache.article import ArticleDetailCache
from cache.user import UserCollectionsCache


article_fields = {
    'art_id': fields.Integer(attribute='id'),
    'title': fields.String(attribute='title'),
    'pubdate': fields.DateTime(attribute='ctime', dt_format='iso8601'),
    'content': fields.String(attribute='content.content'),
    'aut_id': fields.Integer(attribute='user_id'),
    'ch_id': fields.Integer(attribute='channel_id'),
}


class DetailResource(Resource):

    def get(self,article_id):
        """
        详情页面的展示
        :param article_id:
        :return:
        """
        # 获取文章id(路由中传递了)
        # 根据文章id传文章的详细信息
        # article = None
        # try:
        #     article = Article.query.filter(Article.id==article_id,
        #                                Article.status==Article.STATUS.APPROVED).first()
        # except Exception as e:
        #     current_app.logger.error(e)
        #     abort(404)
        #
        # article_dict = marshal(article,article_fields)
        #
        # # 获取用户信息
        # users = UserProfileCache(article_dict['aut_id']).get()
        # # 获取文章作者信息
        # article_dict['aut_name']=users.get('name')
        # article_dict['aut_photo']=users.get('photo')
        article_dict = ArticleDetailCache(article_id).get()

        if article_dict is None:
            abort(404)


        # 初始化
        # 是否关注
        is_followed = False
        # 是否喜欢
        attitude=None
        # 是否收藏
        is_collected = False

        # 再这里缓存所有文章态度信息
        if g.user_id:
            # attitudes = UserArticeAttitudeCache(g.user_id).get_all_articles_attitude()

            # 获取态度缓存
            # str和int类型不一致所以需要将文章id转换为int类型
            # 用get来取key值不会出现异常,字典最好用get来取防止出现异常
            # attitude = attitudes.get(int(article_id))

            attitude = UserArticeAttitudeCache(g.user_id).get_article_attitude(article_id)

            # 获取所有收藏文章id
            total_count,article_ids = UserCollectionsCache(g.user_id).get(1,-1)
            # 在进行判断
            # 因为拿到的article_id是str类型,所以要进行转换
            is_collected = int(article_id) in article_ids

            # 用户浏览记录
            UserHistoryCache(g.user_id).add(article_id)

        article_dict['is_followed']=is_followed
        article_dict['attitude']=attitude
        article_dict['is_collected']=is_collected

        # 返回响应
        return article_dict


class UserFollowingResource(Resource):

    # 必须是登陆用户
    method_decorators = [
        loginrequired
    ]

    def post(self):
        """
        关注用户
        :return:
        """
        # user_id = g.user_id
        # 1. 接收数据,验证数据
        parse=reqparse.RequestParser()
        parse.add_argument('target',location='json',required=True)
        args=parse.parse_args()

        user=None
        # 查询用户
        try:
            user=User.query.get(args.get('target'))
        except Exception as e:
            current_app.logger.error(e)

        if user is None:
            abort(404)

        # 数据入库
        relation = Relation()
        relation.user_id = g.user_id
        relation.target_user_id = args.get("target")
        relation.relation = Relation.RELATION.FOLLOW

        try:
            db.session.add(relation)
            db.session.commit()
        except Exception as e:
            # 若提交失败,回滚并更新关注用户
            db.session.rollback()
            Relation.query.filter(Relation.user_id == g.user_id,
                                  Relation.target_user_id == args.get('target')).update({'relation': Relation.RELATION.FOLLOW})
            db.session.commit()

            # 缓存关注用户
            UserFollowingCache(g.user_id).update(args.get("target"),time.time())

        # 4.返回相应
        return {'target':args.get('target')},201

    # 获取关注用户列表
    def get(self):
        # 获取参数
        page = request.args.get('page', 1)
        per_page = request.args.get('per_page', 10)

        try:
            page = int(page)
            per_page = int(per_page)
        except Exception:
            page = 1
            per_page = 10

        # 查询数据库获取所有的关注列表
        # 通过更新时间utime来排序
        # relations=Relation.query.filter(Relation.user_id==g.user_id,
        #                                 Relation.relation==Relation.RELATION.FOLLOW).order_by(Relation.utime.desc()).all()
        # # 关注的总数
        # total_count=len(relations)
        #
        # # 获取所有关注人员的id
        # target_user_ids=[relation.target_user_id for relation in relations]

        from cache.user import UserFollowingCache
        total_count,target_user_ids = UserFollowingCache(g.user_id).get()


        # 根据分页参数来获取分页数据
        page_target_user_ids=target_user_ids[(page-1)*per_page:page*per_page]
        # 对分页数据进行遍历,获取缓存信息
        results=[]
        for user_id in page_target_user_ids:
            # 根据关注的人的id查询详细信息
            user=UserProfileCache(user_id).get()
            results.append({
                'id': user_id,
                'name': user.get('name'),
                'photo': user.get('photo'),
                'mutual_follow': False  # 是否相互关注
            })

        # 返回相应
        return {'total_count':total_count,'page':page,'per_page':per_page,'results':results}



class UserNotFollowingResource(Resource):
    """
    取消关注用户
    """
    # 必须是登陆用户
    method_decorators = [
        loginrequired
    ]



    def delete(self,target):

        # 1. 查询数据库记录
        Relation.query.filter(Relation.user_id == g.user_id,
                              Relation.target_user_id == target,
                              Relation.relation == Relation.RELATION.FOLLOW).update({'relation': Relation.RELATION.DELETE})
        db.session.commit()

        # 取消关注的同时,还需要清楚缓存
        # -1:表示取消关注
        UserFollowingCache(g.user_id).update(target,time.time(),-1)

        return {"message":"ok"},204


class UserArticleLikesResource(Resource):
    """
    点赞
    """
    method_decorators = [loginrequired]

    def post(self):

        # 1. 接收数据并验证数据
        json_parser = RequestParser()
        json_parser.add_argument('target', required=True, location='json', type=int)
        args = json_parser.parse_args()
        target = args.get("target")

        # 核心逻辑:
        # 3. 查询用户是否对文章有过点赞态度
        user_id = g.user_id
        atti = Attitude.query.filter(Attitude.user_id==user_id,
                                     Attitude.article_id==target).first()
        if atti is None:
            # 4. 如果没有态度,新增数据
            atti = Attitude(
                user_id = user_id,
                article_id = target,
                attitude = Attitude.ATTITUDE.LIKING
            )

            db.session.add(atti)

        else:
            # 5 如果有态度,更新数据
            atti.attitude = Attitude.ATTITUDE.LIKING

        db.session.commit()

        # 更新态度
        UserArticeAttitudeCache(g.user_id).update_field(target,Attitude.ATTITUDE.LIKING)

        # 6. 返回响应
        return {"target":target},201


class UserArticleLikesDeleteResource(Resource):
    """
    取消点赞
    """
    method_decorators = [loginrequired]

    def delete(self,target):

        # 修改数据

        Attitude.query.filter(Attitude.user_id==g.user_id,
                              Attitude.article_id==target,
                              Attitude.attitude==Attitude.ATTITUDE.LIKING).update({"attitude":None})
        db.session.commit()

        # 更新态度
        UserArticeAttitudeCache(g.user_id).update_field(target, -1)

        return {"message":"OK"},204


class UserArticleDislikesResource(Resource):
    """
    不喜欢
    """
    method_decorators = [loginrequired]

    def post(self):
        # 1. 接收并验证数据
        parsers = RequestParser()
        parsers.add_argument("target",required=True,location="json",type=int)
        args = parsers.parse_args()
        target = args.get("target")

        # 根据用户的id和文章的id查询用户态度
        atti = Attitude.query.filter(Attitude.user_id==g.user_id,Attitude.article_id==target).first()

        if atti is None:
            # 如果态度信息不存在新增数据
            atti = Attitude(user_id=g.user_id, article_id=target, attitude=Attitude.ATTITUDE.DISLIKE)
            db.session.add(atti)

        else:
            # 如果存在,更新数据
            atti.attitude = Attitude.ATTITUDE.DISLIKE

        db.session.commit()

        # 更新态度
        UserArticeAttitudeCache(g.user_id).update_field(target,Attitude.ATTITUDE.DISLIKE)

        return {'target': target}, 201


class UserArticleDislikesDeleteResource(Resource):
    """
    取消不喜欢
    """
    method_decorators = [loginrequired]

    def delete(self,target):

        # 更新数据,将态度更新为None
        Attitude.query.filter(Attitude.user_id==g.user_id, Attitude.article_id==target, Attitude.attitude==Attitude.ATTITUDE.DISLIKE).update({'attitude': None})
        db.session.commit()

        # 更新态度
        UserArticeAttitudeCache(g.user_id).update_field(target,-1)

        return {'message': 'OK'}, 204


class UserCollectionsResource(Resource):
    """
    收藏文章
    """
    method_decorators = [loginrequired]

    def post(self):

        # 1. 接收并验证参数
        parsers = RequestParser()
        parsers.add_argument('target', required=True, location='json', type=int)
        args = parsers.parse_args()
        target = args.get("target")

        # 2. 查询数据库
        collection = Collection.query.filter(Collection.user_id==g.user_id,
                                             Collection.article_id==target).first()
        if collection is None:
            # 3. 如果数据不存在,则新增
            collection = Collection()
            collection.user_id = g.user_id
            collection.article_id=target
            collection.is_deleted=False
            db.session.add(collection)

        else:
            # 4. 如果数据存在则修改标记
            collection.is_deleted=False
        db.session.commit()

        # 调用清除缓存方法
        UserCollectionsCache(g.user_id).clear()

        # 返回响应
        return {"target":target}

    def get(self):

        # 接收校验参数
        qs_parser = RequestParser()
        # 添加验证参数 positive:正数
        # int_range    将输入限制为指定范围内的整数
        qs_parser.add_argument('page', type=inputs.positive, required=False, location='args')
        qs_parser.add_argument('per_page', type=inputs.int_range(constants.DEFAULT_ARTICLE_PER_PAGE_MIN,
                                                                 constants.DEFAULT_ARTICLE_PER_PAGE_MAX,
                                                                 'per_page'),
                               required=False, location='args')
        args = qs_parser.parse_args()

        page = 1 if args.page is None else args.page
        per_page = args.per_page if args.per_page else constants.DEFAULT_ARTICLE_PER_PAGE_MIN


        # 查询出来
        # 根据更新时间排序
        # collections = Collection.query.filter(Collection.user_id==g.user_id,
        #                         Collection.is_deleted==False).order_by(Collection.utime.desc()).all()
        # article_ids = []
        # # 获取收藏的所有文章id,为缓存做准备
        # for collection in collections:
        #     article_ids.append(collection.article_id)
        # # 4.分页获取指定的文章id列表
        # page_article_ids=article_ids[(page-1)*per_page:page*per_page]

        total_count,page_article_ids = UserCollectionsCache(g.user_id).get(page,per_page)

        # 5.遍历文章id列表,来获取文章信息
        restuls=[]
        for article_id in page_article_ids:
            article=ArticleDetailCache(article_id).get()
            restuls.append(article)
        # total_count=len(collections)

        # 6.返回响应
        return {'page':page,'per_page':per_page,'results':restuls,'total_count':total_count}


class UserCollectDeleteResource(Resource):
    """
    取消收藏
    """
    method_decorators = [loginrequired]

    def delete(self,target):

        Collection.query.filter(Collection.user_id==g.user_id,
                                Collection.article_id==target).update({"is_deleted":True})

        db.session.commit()

        # 调用清除缓存方法
        UserCollectionsCache(g.user_id).clear()

        return {"message":"OK"},204